#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
'''
@author: yuejl
@application:
@contact: lewyuejian@163.com
@file: parser.py
@time: 2021/3/20 0020 22:50
@desc: 解析
'''
import re
import json
import requests
import yaml
from loguru import logger
from mobs.utils.loadUtils import FileUtils
from wechatapi.exceptions import ParamsError, VariableNotFound, VariableFormatError, TestCaseFormatError
from typing import Dict, Text, List, Any, Callable, Union
from wechatapi.compat import _sort_data_dict_by_custom_order, _sort_testcase_dict_by_custom_order, ensure_testcase_attachment

dolloar_regex_compile = re.compile(r"\$\$")
depend_data_compile = re.compile(r"\$\{(\w+)\}|\$(\w+)")
function_regex_compile = re.compile(r"\$\{(\w+)\(([\$\w\.\-/\s=,]*)\)\}")

def parser_yaml(yaml_content, api_name):
    '''
    整合yaml的格式
    :param yaml_content:
    :param api_name:
    :return:
    '''
    if not isinstance(yaml_content, Dict):
        raise ParamsError(f'yaml 文件的内容不是一个字典')

    test_step = {
        "request": _sort_data_dict_by_custom_order(yaml_content[api_name])

    }
    step = ensure_testcase_attachment(test_step['request'])

    test_step = _sort_testcase_dict_by_custom_order(step)

    return test_step

def _load_yaml_file(filePath):
    with open(filePath, encoding='utf-8') as file_object:
        yml_content = yaml.load(file_object)

        return yml_content

def parser_yaml_data(yaml_file, api_name: Text, func_data: Any = None):


    yaml_content = FileUtils().load_file(yaml_file)
    #yaml_content = json.dumps(yaml_content)
    if not isinstance(yaml_content, Dict):
        raise ParamsError(f'yaml 文件的内容不是一个字典')
    test_step = {
        "request": _sort_data_dict_by_custom_order(yaml_content[api_name])

    }


    step = ensure_testcase_attachment(test_step['request'])

    if func_data:
        # # 带 $ 的变量
        content = get_mapping_variable('depend_data', step).replace('.', '$')
        #print(content)

        #c = regex_findall_depend_data(content, func_data)

        regex = re.sub(depend_data_compile, func_data, step.get('url'))

        step['url'] = regex

        # 将字典转换为json格式
        #data_json = json.dumps(step['data'], ensure_ascii=False)

        #step['data'] = data_json
        step['depend_data'] = func_data
    test_step = _sort_testcase_dict_by_custom_order(step)

    return test_step

# 解析测试用例条目
def parser_testcase_entries(variables_mapping: Dict):
    """
    Args:
        解析测试用例
    Return：
        action entries = 1， 返回 test_case_list 的第一个元素 >>> dict type.
        action entries > 1,  返回 test_case_list >>> list type.
    Examples:
        >>> yaml_file = r""
        >>> test_step_data = parser_yaml_data(yaml_file)
        >>> parser_testcase_entries(test_step_data)
    """
    test_case_list = []
    if isinstance(variables_mapping, Dict):
        if not isinstance(variables_mapping.get("action"), (List, Dict)):
            raise VariableFormatError('测试数据格式异常 >>> {0}'.format(variables_mapping.get("action")))
        elif isinstance(variables_mapping.get("action"), Dict):
            test_case_list.append(variables_mapping)
        elif isinstance(variables_mapping.get("action"), List):
            if not variables_mapping.get("action"):
                raise TestCaseFormatError(
                            f'Invalid action >>> {variables_mapping.get("action")}'
                        )
            else:
                if "action" in variables_mapping:
                    for x_item in variables_mapping.get("action"):
                        test_step = {
                            "apiname": variables_mapping.get("apiname")
                        }
                        if "method" in variables_mapping:
                            test_step["method"] = variables_mapping.get("method")
                        if "url" in variables_mapping:
                            test_step["url"] = variables_mapping.get("url")
                        if "tips" in variables_mapping:
                            test_step["tips"] = variables_mapping.get("tips")
                        if "depend_data" in variables_mapping:
                            test_step["depend_data"] = variables_mapping.get("depend_data")
                        if "name" in variables_mapping:
                            test_step["name"] = variables_mapping.get("name")
                        if "descript" in variables_mapping:
                            test_step["descript"] = variables_mapping.get("descript")
                        if "case_id" in x_item:
                            test_step["case_id"] = x_item.get("case_id")
                        if "case_title" in x_item:
                            test_step["case_title"] = x_item.get("case_tile")
                        if "priority" in x_item:
                            test_step["priority"] = x_item.get("priority")
                        if "demo" in x_item:
                            test_step["demo"] = x_item.get("demo")
                        if "doc" in x_item:
                            test_step["doc"] = x_item.get("doc")
                        if "json" in x_item:
                            if isinstance(x_item.get("json"), List):
                                if not x_item.get("json"):
                                    raise TestCaseFormatError(
                                        f'Invalid action >>> json >>> {x_item.get("json")}'
                                    )
                                else:
                                    for x in x_item.get("json"):
                                        test_step["json"] = x
                        if "expect" in x_item:
                            test_step["expect"] = x_item.get("expect")

                        test_case_list.append(test_step)
    if not test_case_list:
        raise TestCaseFormatError(
            f'Invalid test step >>>  {test_case_list}'
        )
    elif len(test_case_list) == 1:
        return test_case_list[0]
    else:
        return test_case_list


def convert_variables(variables: Union[Dict, List, Text]) -> Dict:
    '''
    列表的元素 >>> 字典

    :param variables:
    :return:
    '''
    if isinstance(variables, Dict):
        return variables
    if isinstance(variables, List):
        variables_dict: Dict = {}
        for var_item in variables:
            if not isinstance(var_item, str) or len(variables) != 1:
                raise VariableFormatError(
                    f"Invalid variables format: {variables}"
                )
            variables_dict.update(json.loads(var_item))
        return variables_dict

def regex_findall_depend_data(raw_string: Text, variables: Any) -> Union[Dict, List]:
    """ extract all variable names from content, which is in format $variable

        替换变量

    Args:
        raw_string (str): string content

    Returns:
        list: variables list extracted from string content

    Examples:
        >>> regex_findall_variables("$variable")
        ["variable"]

        >>> regex_findall_variables("/blog/$postid")
        ["postid"]

        >>> regex_findall_variables("/$var1/$var2")
        ["var1", "var2"]

        >>> regex_findall_variables("abc")
        []

    """
    data_list = []
    try:
        # 从索引0开始检测字符串中是否包含子字符串$，返回$在字符串的索引
        match_start_position = raw_string.index("$", 0)

    except ValueError:

        return []


    while match_start_position < len(raw_string):
        # Notice: notation priority
        # $$ > $var

        # search $$
        # re.match 尝试从字符串的起始位置匹配一个模式，如果不是起始位置匹配成功的话，match()就返回none。 span(0,1) 第一次出现的开始索引与结束索引i-1
        # 此处 是用来匹配当出现多个$ 的时候
        dollar_match = dolloar_regex_compile.match(raw_string, match_start_position)
        if dollar_match:
            match_start_position = dollar_match.end()
            continue
        # search variable like ${var} or $var
        var_match = depend_data_compile.match(raw_string, match_start_position)
        if var_match:

            var_name = var_match.group(1) or var_match.group(2)

            if isinstance(variables, Dict):
                gus = var_name.replace(var_name, json.dumps(variables))
                data_list.append(gus)
            else:
                gus = var_name.replace(var_name, variables)
                data_list.append(gus)


            match_start_position = var_match.end()

            continue
        curr_position = match_start_position
        try:
            # find next $ location
            match_start_position = raw_string.index("$", curr_position + 1)
        except ValueError:
            # break while loop
            break
    #result = convert_variables(data_list)
    return data_list

def replace_mapping_variable(variables_mapping: Dict, extractors: Dict):
    if isinstance(variables_mapping, Dict):
        temp = None
        for k_name, v_value in variables_mapping.items():
            #print(v_value)
            res = regex_findall_depend_data(v_value, extractors)
            temp = [json.loads(x) for x in res]

        return temp



def get_mapping_variable(
    variable_name: Text, variables_mapping: Dict[Text, Any]
) -> Any:
    """ get variable from variables_mapping. 从字典获取变量

    Args:
        variable_name (str): variable name
        variables_mapping (dict): variables mapping

    Returns:
        mapping variable value.

    Raises:
        exceptions.VariableNotFound: variable is not found.

    """

    try:
        return variables_mapping[variable_name]
    except KeyError:
        raise VariableNotFound(
            f"{variable_name} not found in {variables_mapping}"
        )



class ResponseObject(object):


    def extract(self, name, extractors: Dict[Text, Text]) -> Dict[Text, Any]:
        if not extractors:
            return {}

        extract_mapping = {}
        if isinstance(extractors, Dict):
            if name in extractors:
                result = extractors[name]
                extract_mapping.update({name: result})
        logger.info(f"extract mapping: {extract_mapping}")
        return extract_mapping

if __name__ == '__main__':
    a = FileUtils.load_file(r'D:\CodeBase\auto\WechatApi\wechatapi\data\testdatas\test_member.yaml')
    # print(a)
    # aa = parser_yaml(a, 'create_member')
    # print(aa)


    #bb = get_mapping_variable('depend_data', aa)


    #aaa = 'https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=${depend_data}'
    # b = "access_token"
    b_1 = "xb9xiOhqsUimwRaDjSxqdTz-qFFORAIKg0keChVSLDFbk7R_PLXZoMfuzd95akd4RxdIeU7t0BQzsqBJwQ24mgJBXEf0DsukCjvRtlyhZFxUoIHWEd52-F1ilDhV_CWW4_i3Brm-PT9QD-RfxOusBNdLnp80hUw88Ejtus1i87Cnv_2wTMIcX2YUX5ZPf2Od-iFrejODrTT2dKnS7hh1ig"
    #c = regex_findall_depend_data(aaa, b_1)
    #print(c)
    #print(convert_variables(c))

    res = parser_yaml_data(r"D:\CodeBase\auto\WechatApi\wechatapi\data\testdatas\test_member.yaml", 'create_member', b_1)
    print(type(res))
    print(res)
    resp = parser_testcase_entries(res)
    print(resp)
    for i in resp:
        print(type(i))
        for k,v in i.items():
            print(type(v))

    # from wechatapi.api.get_token import WeChat
    # data = WeChat().get_token()
    # print(type(data))
    # resp = ResponseObject()
    # print(resp.extract('access_token',data))